package com.jojo.bubble.controller.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
//import com.github.wxpay.sdk.WXPayUtil;
import com.jojo.bubble.common.domain.AjaxResult;
import com.jojo.bubble.common.enums.JsonResultEnum;
import com.jojo.bubble.common.pages.PageUtil;
import com.jojo.bubble.entity.*;
import com.jojo.bubble.service.*;
import com.jojo.bubble.utils.OrderNumUtil;
import com.jojo.bubble.utils.PayResponseUtils;
import com.jojo.bubble.utils.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.util.Base64Utils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.security.GeneralSecurityException;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.jojo.bubble.utils.AlipayTradeWapPay.aliAppletPay;

/**
 * @Author JoJo
 * @Date 2023/7/26 13:12
 * @Description
 * @Version 1.0
 */
@RestController
@RequestMapping("/api/order")
@Slf4j
public class OrderApiController {
    @Resource
    OrderService orderService;
    @Resource
    private AgentService agentService;

    @Resource
    private ShopService shopService;

    @Resource
    private DevService devService;
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;

    @PostMapping("/detail")
    public AjaxResult getOrderDetail(Order order) {
        Order record = orderService.getInfoByOrderNo(order.getOrderNo());
        if (ObjectUtils.isEmpty(record)) {
            return AjaxResult.error("订单不存在");
        }
//        log.info(record.getOrderNo());
//        orderService.updateStatus(record.getId());


        Dev dev = devService.getInfo(record.getDevId());
        OrderVo orderVo = new OrderVo();
        orderVo.setDevCode(dev.getCode());
        orderVo.setStatus(record.getStatus());
        orderVo.setMin(Integer.valueOf(record.getRemark()));

        return AjaxResult.success(orderVo);
    }

    @PostMapping("/insert")
    public AjaxResult insert(Order order) {
//        System.out.println("order" + order);
        User user = userService.getInfo(order.getUserId());
        if (ObjectUtils.isEmpty(user)) {
            return AjaxResult.error("用户不存在");
        }
        Dev dev = devService.getInfo(order.getDevId());
        if(ObjectUtils.isEmpty(dev)) {
            return AjaxResult.error("设备未连接");
        } else {
            if (dev.getStatus() == 0) {
                return AjaxResult.error("设备未连接");
            } else if (dev.getStatus() == 2) {
                return AjaxResult.error("设备SIM卡错误");
            } else {
                order.setAgentId(dev.getAgentId());
            }
        }
        String orderStr = OrderNumUtil.getInstance().GenerateOrder();
        order.setOrderNo(orderStr);
        orderService.insert(order);
        return AjaxResult.success(order);
    }

    @GetMapping("/list")
    public AjaxResult getList(Order record,@RequestParam(defaultValue = "0",value = "needLevel") Integer needLevel, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum, @RequestParam(defaultValue = "10",value = "pageSize") Integer pageSize) {

        List<Order> orders = new ArrayList<>();
//        return AjaxResult.success(idList);
        record.setStatus(1);
        Pageable pageable = PageRequest.of(pageNum-1,pageSize);
        if(needLevel==1){
            System.out.println("needLEVELLL");
            List<Agent> agentList =  agentService.queryOverById(record.getAgentId());
            List <Integer> idList = new ArrayList<>();
            agentList.forEach((agent -> {
                idList.add(agent.getId());
            }));
            record.setAgentId(null);
            orders = orderService.queryAllByLimit(record,idList,pageable);
        }
        else{
            orders = orderService.queryAllByLimit(record,null,pageable);
        }
        for (Order order : orders) {
            User user = userService.getInfo(order.getUserId());
            if (!ObjectUtils.isEmpty(user)) {
                order.setUsername(user.getNickname());
            }
            Dev dev = devService.getInfo(order.getDevId());
            if (!ObjectUtils.isEmpty(dev)) {
                order.setDevCode(dev.getCode());
            }
            Agent agent = agentService.getInfo(order.getAgentId());
            if (!ObjectUtils.isEmpty(agent)) {
                order.setAgentName(agent.getName());
            } else {
                order.setAgentName("");
            }
            Shop shop = shopService.getInfo(order.getShopId());
            if (!ObjectUtils.isEmpty(shop)) {
                order.setShopName(shop.getName());
            } else {
                order.setShopName("");
            }
        }
        int all = orderService.count(record);
        PageUtil page = new PageUtil(orders,all,pageSize,pageNum);
        return AjaxResult.success(page);

    }
    @PostMapping("/aliPay")
    public AjaxResult aliPay(Order order) throws AlipayApiException {
        Order record = orderService.getInfoByOrderNo(order.getOrderNo());
        if (ObjectUtils.isEmpty(record)) {
            return AjaxResult.error("订单不存在");
        }
        User user = userService.getInfo(record.getUserId());
        if (ObjectUtils.isEmpty(user)) {
            return AjaxResult.error(JsonResultEnum.USER_NULL);
        }
        BigDecimal price = record.getMoney();
        Dev dev = devService.getInfo(record.getDevId());
        String runTime = record.getRemark();
        String res = aliAppletPay(order.getOrderNo(), price.toString(), dev.getCode(), runTime);
        if (StringUtils.hasLength(res)) {
            return AjaxResult.successData(res);
        } else {
            return AjaxResult.error("调用失败");
        }

    }

    @PostMapping("/recharge")
    public AjaxResult recharge() {

        return AjaxResult.success();
    }

    /**
     * 支付完成回调验证操作
     *
     * @param request
     * @return void
     * @throws Exception
     * @author 有梦想一起实现
     */
    @RequestMapping("/ali/notifyUrl")
    public String Notify(HttpServletRequest request) {
        System.out.println("支付宝回调");
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);
        JSONObject json = JSONObject.parseObject(paramsJson);
        Order order = orderService.getInfoByOrderNo(json.getString("out_trade_no"));
        if (order != null) {
            //如果付款成功
            if (json.getString("trade_status").equals("TRADE_SUCCESS")) {
                order.setStatus(1);
                orderService.update(order);
                updateAgentBalance(order.getOrderNo());
            } else {
                //修改失败参数
                order.setStatus(2);
                orderService.update(order);
            }
        }
        System.out.println("支付宝回调，{}" + paramsJson);
        return "success";
    }

    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<>();

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }

    /**
     * @desc: 微信支付
     * @param: [order]
     * @return: com.jojo.ocr_car.common.domain.AjaxResult
     * @date: 2022/12/9 16:37
     */
    @PostMapping("/wechatPay")
    public AjaxResult wechatPay(Order order) throws IOException {
        Order record = orderService.getInfoByOrderNo(order.getOrderNo());
        if (ObjectUtils.isEmpty(record)) {
            return AjaxResult.error("订单不存在");
        }
        User user = userService.getInfo(record.getUserId());
        if (ObjectUtils.isEmpty(user)) {
            return AjaxResult.error(JsonResultEnum.USER_NULL);
        }
        Integer price = record.getMoney().multiply(new BigDecimal(100)).intValue();
        HashMap<String, String> map = WeChatUtil.jsapiPayV3(order.getOrderNo(), price, user.getOpenId(), "任你游泡泡机");
//        System.out.println("map:" + map.get("nonceStr"));
        return AjaxResult.success(map);
//        if ("SUCCESS".equals(map.get("return_code"))) {
//            return AjaxResult.success(map);
//        } else {
//            return AjaxResult.error(map.get("return_code"));
//        }
    }

//    /**
//     * @desc: 支付回调
//     * @param: [unifiedorderUrl, requestXml]
//     * @return: java.lang.String
//     * @date: 2022/12/10 17:06
//     */
//    @PostMapping("/notifyUrl")
//    public String notifyUrl(String requestXml) {
//        System.out.print("进入支付h5回调=====================");
//
//        //判断接受到的result_code是不是SUCCESS,如果是,则返回成功,具体业务具体分析,修改订单状态
//
//        // 通知微信.异步确认成功.必写.不然会一直通知后台.
//        String resXml = WeChatUtil.notifyUrl("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXml);
//        return resXml; //或者 return "success";
//    }

    /**
     * 微信支付结果回调地址
     *
     * @param request
     */
    @PostMapping(value = "/notify")
    public Map<String, String> payNotify(HttpServletRequest request) {

        Map<String, String> map = new HashMap<>(2);
        try {
            //微信返回的请求体
            String body = getRequestBody(request);
            //如果验证签名序列号通过
//            if (verifiedSign(request, body)) {
                //微信支付通知实体类
                PayNotifyVO payNotifyVO = JSONObject.parseObject(body, PayNotifyVO.class);
                log.info("payNotifyVO:",payNotifyVO.getEvent_type());
                //如果支付成功
                if ("TRANSACTION.SUCCESS".equals(payNotifyVO.getEvent_type())) {
                    //通知资源数据
                    PayNotifyVO.Resource resource = payNotifyVO.getResource();
                    //解密后资源数据
                    String notifyResourceStr = PayResponseUtils.decryptResponseBody(resource.getAssociated_data(), resource.getNonce(), resource.getCiphertext());
                    //通知资源数据对象
                    NotifyResourceVO notifyResourceVO = JSONObject.parseObject(notifyResourceStr, NotifyResourceVO.class);
                    log.info("notifyResourceVO", notifyResourceVO);
                    //查询订单 可以优化把订单放入redis
                    Order order = orderService.getInfoByOrderNo(notifyResourceVO.getOut_trade_no());
                    if (order != null) {
                        //如果付款成功
                        if ("SUCCESS".equals(notifyResourceVO.getTrade_state())) {
                            order.setStatus(1);
                            orderService.update(order);
                            updateAgentBalance(order.getOrderNo());
                        } else {
                            //修改失败参数
                            order.setStatus(2);
                            orderService.update(order);
                        }
                    }
                } else {
                    log.info("微信返回支付错误摘要：" + payNotifyVO.getSummary());
                }
//            }

            //通知微信正常接收到消息,否则微信会轮询该接口
            map.put("code", "SUCCESS");
            map.put("message", "");
            return map;

        } catch (IOException e) {
            e.printStackTrace();
        }
//        catch (GeneralSecurityException e) {
//            throw new RuntimeException(e);
//        } catch (ParseException e) {
//            throw new RuntimeException(e);
//        }
        return map;
    }

    /**
     * 验证微信签名
     *
     * @param request
     * @param body
     */
    private boolean verifiedSign(HttpServletRequest request, String body) throws GeneralSecurityException, ParseException, IOException {
        //微信返回的证书序列号
        String serialNo = request.getHeader("Wechatpay-Serial");
        //微信返回的随机字符串
        String nonceStr = request.getHeader("Wechatpay-Nonce");
        //微信返回的时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //微信返回的签名
        String wechatSign = request.getHeader("Wechatpay-Signature");
        //组装签名字符串
        String signStr = Stream.of(timestamp, nonceStr, body)
                .collect(Collectors.joining("\n", "", "\n"));
        //当证书容器为空 或者 响应提供的证书序列号不在容器中时  就应该刷新了
        if (StaticParameter.certificateMap.isEmpty() || !StaticParameter.certificateMap.containsKey(serialNo)) {
            StaticParameter.certificateMap = PayResponseUtils.refreshCertificate();
        }
        //根据序列号获取平台证书
        X509Certificate certificate = StaticParameter.certificateMap.get(serialNo);
        //获取失败 验证失败
        if (certificate == null) {
            return false;
        }
        //SHA256withRSA签名
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(certificate);
        signature.update(signStr.getBytes());
        //返回验签结果
        return signature.verify(Base64Utils.decodeFromString(wechatSign));
    }

    /**
     * 获取请求文体
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestBody(HttpServletRequest request) throws IOException {
        ServletInputStream stream = null;
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            throw new IOException("读取返回支付接口数据流出现异常！");
        } finally {
            reader.close();
        }
        return sb.toString();
    }

    private void updateAgentBalance(String order_no){
        BigDecimal sysPer = new BigDecimal("0.994");//系统手续费
        Order order = orderService.getInfoByOrderNo(order_no);
        Agent agent;
        if(order.getAgentId()!=null){
            agent = agentService.getInfo(order.getAgentId());
        }
        else{
            agent=null;
        }

        Dev dev = devService.getInfo(order.getDevId());

        if (!ObjectUtils.isEmpty(agent) && !(dev.getAgentId().equals(dev.getOwnAgentId()))) {
            if (agent.getLevel() == 0) {
                // 找出一级代理商
                Agent father1 = agentService.getInfo(agent.getSupAgentId());
                if (!ObjectUtils.isEmpty(father1)){
//                    有一级代理商的情况，获取分成设置
                    Role role1 = roleService.getInfo(father1.getType());
//                    计算一级应该分的钱
                    BigDecimal father1Money = order.getMoney().multiply(role1.getPrice());
                    order.setFirstMoney(father1Money);
//                    更新一级余额
                    father1.setBalance(father1.getBalance().add(father1Money));
                    agentService.update(father1);
//                    找二级
                    Agent father2 = agentService.getInfo(father1.getSupAgentId());
                    if (!ObjectUtils.isEmpty(father2)){ //如果有二级，就继续计算，没有就结束，算出本身应该得到的钱
                        Role role2 = roleService.getInfo(father2.getType());
                        BigDecimal father2Money = order.getMoney().multiply(role2.getPrice2());
//                    更新二级余额
                        father2.setBalance(father2.getBalance().add(father2Money));
                        order.setSecondMoney(father2Money);
                        agentService.update(father2);
//                        计算本身的钱
                        BigDecimal ownMoney = order.getMoney().multiply(sysPer).subtract(father1Money).subtract(father2Money);
                        agent.setBalance(agent.getBalance().add(ownMoney));
                        agentService.update(agent);
                    }
                    else{
//                        计算本身的钱
                        BigDecimal ownMoney = order.getMoney().multiply(sysPer).subtract(father1Money);
                        agent.setBalance(agent.getBalance().add(ownMoney));
                        agentService.update(agent);
                    }
                    orderService.update(order);
                }
            } else {
                //商户
                // 变更商户和代理商金额
                Agent father = agentService.getInfo(agent.getSupAgentId());
                if (!ObjectUtils.isEmpty(father)){
                    BigDecimal ownMoney = order.getMoney().multiply(agent.getPercent());// 商户自己应得的钱
                    agent.setBalance(agent.getBalance().add(ownMoney));
                    agentService.update(agent);
//                    上级分成
                    BigDecimal agentMoney = order.getMoney().multiply(sysPer.subtract(agent.getPercent()));
                    father.setBalance(father.getBalance().add(agentMoney));
                    agentService.update(father);
                    order.setFirstMoney(agentMoney);
                    orderService.update(order);
                }
                else{
                    //应该没有这种情况
                }
            }
        }
//        不分成
        else{
            BigDecimal ownMoney = order.getMoney().multiply(sysPer);// 商户自己应得的钱
            agent.setBalance(agent.getBalance().add(ownMoney));
            agentService.update(agent);
        }
    }
//    @PostMapping("/refund")
//    public AjaxResult wxRefund(Integer id) throws Exception {
//        Order order = orderService.getInfo(id);
//        if (order == null) {
//            return AjaxResult.error(JsonResultEnum.ORDER_NULL);
//        }
//        User user = userService.getInfo(order.getUserId());
//        if (user == null) {
//            return AjaxResult.error(JsonResultEnum.USER_NULL);
//        }
//        Map<String, String> map = new HashMap<>();
//        if (order.getStatus() == 1) {
//            map = WeChatUtil.refund(order);
//            if (map.get("success").equals("REFUNDS")) {
//                order.setStatus(3);
//                orderService.update(order);
//            }
//        }
//
//
//        return AjaxResult.successData(map);
//    }

}
